Skip to content

Add missing features and new endpoints#129

Open
wscourge wants to merge 5 commits intomainfrom
wiktor/pip-310-python-sdk-feature-updates
Open

Add missing features and new endpoints#129
wscourge wants to merge 5 commits intomainfrom
wiktor/pip-310-python-sdk-feature-updates

Conversation

@wscourge
Copy link
Contributor

@wscourge wscourge commented Mar 17, 2026

Summary

  • PIP-304: Expose errors field on LineItem and Transaction schemas (Invoice already had it)
  • PIP-120 / PIP-76: Add id, churn_recognition, churn_when_zero_mrr fields to Account schema; support include query param on /account
  • Invoice endpoints: Add Invoice.update_status (PATCH) and Invoice.disable (PATCH /invoices/{uuid}/disable)
  • SubscriptionEvent: Add destroy() / modify() wrappers that accept flat params instead of requiring subscription_event: {...} envelope; add disable() / enable() convenience methods

Test plan

  • Existing 103 tests still pass
  • Added 27 new tests covering happy paths, error paths (404), edge cases (None/absent errors, envelope passthrough, no-mutation, missing uuid validation)
  • 130 total tests passing

Manual testing instructions

Prerequisites

pip3 install chartmogul
# or install from this branch:
pip3 install -e .
import chartmogul
config = chartmogul.Config('YOUR_API_KEY')

Replace YOUR_API_KEY with a real API key from your ChartMogul account. You'll need a test account with at least one data source, customer, and invoice already created.


PIP-304: Validation errors on LineItem and Transaction

What to test: When retrieving an invoice, line_items[].errors and transactions[].errors are now accessible (previously only invoice.errors was exposed).

# Retrieve an invoice (use a real invoice UUID from your account)
invoice = chartmogul.Invoice.retrieve(config, uuid='inv_YOUR_UUID').get()

# Check line item errors field is accessible
for li in invoice.line_items:
    print(f"LineItem {li.uuid}: errors = {getattr(li, 'errors', 'NOT SET')}")

# Check transaction errors field is accessible
for tx in invoice.transactions:
    print(f"Transaction {tx.uuid}: errors = {getattr(tx, 'errors', 'NOT SET')}")

Expected: Each line item and transaction prints its errors value (None for valid items, or a dict of validation errors). No AttributeError is raised.


PIP-120: Account ID in response

What to test: Account.retrieve() now exposes the id field.

account = chartmogul.Account.retrieve(config).get()
print(f"Account ID: {account.id}")
print(f"Account name: {account.name}")

Expected: account.id prints a string like "acct_...". No AttributeError.


PIP-76: Include params on Account endpoint

What to test: Pass include query param to retrieve additional account fields.

account = chartmogul.Account.retrieve(
    config,
    include='churn_recognition,churn_when_zero_mrr'
).get()

print(f"Churn recognition: {account.churn_recognition}")
print(f"Churn when zero MRR: {account.churn_when_zero_mrr}")

Expected: Both fields are returned with string values (e.g. "immediate", "ignore"). Without include, these fields would not be present in the response.


Invoice update-status endpoint

What to test: Invoice.update_status() sends a PATCH to /invoices/{uuid}.

# Update an invoice's status (use a real invoice UUID)
result = chartmogul.Invoice.update_status(
    config,
    uuid='inv_YOUR_UUID',
    data={'disabled': True}
).get()

print(f"Invoice {result.uuid} disabled: {result.disabled}")

Expected: The invoice is updated and result.disabled is True. The API returns the full invoice object.


Invoice disable endpoint

What to test: Invoice.disable() sends a PATCH to /invoices/{uuid}/disable with no request body.

result = chartmogul.Invoice.disable(
    config,
    uuid='inv_YOUR_UUID'
).get()

print(f"Invoice {result.uuid} disabled: {result.disabled}")

Expected: The invoice is disabled. result.disabled is True.

Error case — missing uuid:

try:
    chartmogul.Invoice.disable(config)
except chartmogul.ArgumentMissingError as e:
    print(f"Correctly raised: {e}")

Expected: Raises ArgumentMissingError with message about missing uuid parameter.


SubscriptionEvent: flat params for modify/destroy

What to test: New destroy() and modify() accept flat params without the subscription_event envelope.

# Modify with flat params (no envelope needed)
result = chartmogul.SubscriptionEvent.modify(
    config,
    data={'id': YOUR_EVENT_ID, 'amount_in_cents': 2000}
).get()
print(f"Modified event {result.id}, amount: {result.amount_in_cents}")

# Old envelope style still works
result2 = chartmogul.SubscriptionEvent.modify(
    config,
    data={'subscription_event': {'id': YOUR_EVENT_ID, 'amount_in_cents': 1000}}
).get()
print(f"Modified event {result2.id}, amount: {result2.amount_in_cents}")

# Destroy with flat params
chartmogul.SubscriptionEvent.destroy(
    config,
    data={'id': YOUR_EVENT_ID}
).get()
print("Event destroyed")

Expected: Both flat and envelope-wrapped calls work. The SDK auto-wraps flat params into {"subscription_event": {...}} before sending.


SubscriptionEvent: disable/enable toggling

What to test: New disable() and enable() convenience methods.

# Disable an event
result = chartmogul.SubscriptionEvent.disable(
    config,
    data={'id': YOUR_EVENT_ID}
).get()
print(f"Event {result.id} after disable")

# Enable it back
result = chartmogul.SubscriptionEvent.enable(
    config,
    data={'id': YOUR_EVENT_ID}
).get()
print(f"Event {result.id} after enable")

# Also works with external_id + data_source_uuid
result = chartmogul.SubscriptionEvent.disable(
    config,
    data={
        'external_id': 'YOUR_EXT_ID',
        'data_source_uuid': 'ds_YOUR_UUID'
    }
).get()
print(f"Event {result.id} disabled via external_id")

Expected: Each call succeeds. The SDK sets disabled: true/false inside the subscription_event envelope automatically.


🤖 Generated with Claude Code

wscourge and others added 5 commits March 17, 2026 17:04
Invoice already has an `errors` field, but LineItem and Transaction did
not. Add `errors = fields.Dict(allow_none=True)` to both schemas so
validation errors returned by the API are accessible on nested objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `id` field to Account schema so the account identifier is accessible.
Add `churn_recognition` and `churn_when_zero_mrr` fields to support the
optional `include` query parameter on the /account endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Invoice.update_status (PATCH /invoices/{uuid}) for updating invoice
status and Invoice.disable (PATCH /invoices/{uuid}/disable) for
disabling invoices.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add SubscriptionEvent.destroy() and .modify() that accept flat params
(e.g. data={"id": 123}) and auto-wrap in the subscription_event
envelope. The old _with_params methods are preserved for backwards
compatibility.

Add SubscriptionEvent.disable() and .enable() convenience methods
for toggling the disabled state of subscription events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add edge case, error path, and backwards-compatibility tests:

Invoice:
- Verify update_status request body is sent correctly
- 404 error paths for update_status and disable
- Verify disable sends no request body
- LineItem/Transaction errors=None and errors-absent cases

SubscriptionEvent:
- Flat destroy/modify with external_id+data_source_uuid
- Passthrough when caller already wraps in envelope (no double-wrap)
- disable/enable with external_id+data_source_uuid identification

Account:
- Graceful handling when id field absent from response
- Single include param

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@wscourge wscourge marked this pull request as ready for review March 17, 2026 16:16
@wscourge wscourge requested a review from Copilot March 17, 2026 16:18
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Python SDK to support additional API response fields and adds/adjusts client methods for invoice and subscription event operations, with accompanying test coverage.

Changes:

  • Add deserialization support for errors on invoice line items/transactions and for additional account fields (id, churn settings).
  • Add invoice endpoints for updating status and disabling invoices.
  • Add SubscriptionEvent.destroy/modify/disable/enable helpers that accept “flat” params and wrap them in the required subscription_event envelope, plus tests for these behaviors.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
chartmogul/api/transaction.py Adds errors field support on Transaction schema.
chartmogul/api/invoice.py Adds errors support on invoice-related schemas and introduces update_status / disable methods.
chartmogul/api/account.py Extends Account schema with optional id and churn-related fields.
chartmogul/api/subscription_event.py Adds wrapper methods to accept flat params and to enable/disable subscription events.
test/api/test_invoice.py Adds tests for nested errors fields and new invoice status/disable endpoints.
test/api/test_account.py Adds tests for newly supported account fields and include query behavior.
test/api/test_subscription_event.py Adds tests for flat-parameter wrapping and enable/disable helpers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@wscourge wscourge changed the title Wiktor/pip 310 python sdk feature updates Add missing SDK features (PIP-304, PIP-120, PIP-76) and new endpoints Mar 18, 2026
@wscourge wscourge changed the title Add missing SDK features (PIP-304, PIP-120, PIP-76) and new endpoints Add missing features and new endpoints Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants